from typing import List, Dict
from uuid import UUID

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.db.postgres import get_session
from app.models import Menu, RoleMenu, UserRole, UserAccount
from app.schemas.menu import MenuCreate, MenuRead, MenuNode, MenuUpdate
from app.core.security import get_current_user


router = APIRouter(prefix="/menus", tags=["menus"])


@router.get("", response_model=List[MenuRead])
async def list_menus(session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    result = await session.execute(select(Menu).order_by(Menu.order_index))
    menus = result.scalars().all()
    return [MenuRead(id=m.id, parent_id=m.parent_id, name=m.name, path=m.path, icon=m.icon, order_index=m.order_index, enabled=m.enabled) for m in menus]


@router.post("", response_model=MenuRead)
async def create_menu(payload: MenuCreate, session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    m = Menu(parent_id=payload.parent_id, name=payload.name, path=payload.path, icon=payload.icon, order_index=payload.order_index, enabled=payload.enabled)
    session.add(m)
    await session.flush()
    await session.refresh(m)
    await session.commit()
    return MenuRead(id=m.id, parent_id=m.parent_id, name=m.name, path=m.path, icon=m.icon, order_index=m.order_index, enabled=m.enabled)


@router.put("/{menu_id}", response_model=MenuRead)
async def update_menu(menu_id: UUID, payload: MenuUpdate, session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    m = await session.get(Menu, menu_id)
    if not m:
        from fastapi import HTTPException
        raise HTTPException(status_code=404, detail="菜单不存在")
    for k, v in payload.dict(exclude_unset=True).items():
        setattr(m, k, v)
    await session.flush()
    await session.refresh(m)
    await session.commit()
    return MenuRead(id=m.id, parent_id=m.parent_id, name=m.name, path=m.path, icon=m.icon, order_index=m.order_index, enabled=m.enabled)


def build_menu_tree(items: List[Menu]) -> List[MenuNode]:
    node_map: Dict[UUID, MenuNode] = {}
    roots: List[MenuNode] = []
    for m in items:
        node_map[m.id] = MenuNode(id=m.id, name=m.name, path=m.path, icon=m.icon, children=[])
    for m in items:
        node = node_map[m.id]
        if m.parent_id and m.parent_id in node_map:
            node_map[m.parent_id].children.append(node)
        else:
            roots.append(node)
    # 排序：按order_index
    order_index_map = {m.id: m.order_index for m in items}
    for n in node_map.values():
        n.children.sort(key=lambda c: order_index_map.get(c.id, 0))
    roots.sort(key=lambda r: order_index_map.get(r.id, 0))
    return roots


@router.get("/tree", response_model=List[MenuNode])
async def my_menu_tree(session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    # 通过用户角色查询其可见菜单集合
    ur = UserRole
    rm = RoleMenu
    result = await session.execute(
        select(Menu).join(rm, rm.menu_id == Menu.id).join(ur, ur.role_id == rm.role_id).where(ur.user_id == current_user.id, Menu.enabled == True).order_by(Menu.order_index)
    )
    menus = result.scalars().all()
    return build_menu_tree(menus)
